import json

# Create your views here.
import os

import logging
import requests
from django.core.exceptions import ObjectDoesNotExist
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework import viewsets, mixins
from rest_framework.pagination import PageNumberPagination
from rest_framework.parsers import MultiPartParser, FormParser

from apiTest.serializers import *
from common.paginatedViewMixin import PaginatedViewMixin
from common.standard_pagination import StandardPagination
from devops import settings
from utils import response_body_utils
from utils.response_body_utils import get_error_response, get_success_response
from . import models as ApiTestModels, send_http_request
from .api_parsing import analysis_json
from .case_runnning import tes_case_run, group_run

logging = logging.getLogger("log")


class ApiInfoView(viewsets.GenericViewSet, PaginatedViewMixin):
    queryset = ApiInfo.objects.all().filter(is_deleted=0).order_by("-update_time")
    serializer_class = ApiInfoModelSerializer
    pagination_class = StandardPagination  # 使用自定义的分页类

    def add(self, request):
        name = request.data["name"]
        project_id = request.data["project_id"]
        if self.get_queryset().filter(name=name, project_id=project_id, is_deleted=0).first():
            return get_error_response(response_body_utils.DATA_DUPLICATION)
        # 反序列化
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return get_success_response("")
        else:
            print(serializer.errors)
        return get_success_response("")

    def page(self, request):
        get_queryset = self.get_queryset()
        # 定义一个字典来映射GET参数到查询字段
        filter_fields = {
            'api_suite_id': 'api_suite_id',
            'project_id': 'project_id',
            'name': 'name__icontains',
            'path': 'path__icontains',
        }
        # 遍历GET参数并应用过滤
        for key, field in filter_fields.items():
            value = request.GET.get(key)
            if value:
                get_queryset = get_queryset.filter(**{field: value})
        return super().base_page(request, get_queryset)

    def list(self, request):
        api_infos = self.get_queryset()
        data = self.get_serializer(api_infos, many=True).data
        return get_success_response(data)

    def update(self, request):
        req_data = request.data

        if self.get_queryset().filter(id=req_data["id"]).first():
            api_info = ApiInfo.objects.get(id=req_data["id"])
            serializer = ApiInfoModelSerializer(api_info, data=req_data, partial=True)
            if serializer.is_valid():
                serializer.save()
            else:
                return get_error_response(response_body_utils.PARAMS_MISSING)
            return get_success_response("")
        else:
            return get_error_response(response_body_utils.DATA_ABSENT)

    def delete(self, request, **kwargs):

        if kwargs.get("pk"):
            self.get_queryset().filter(id=kwargs["pk"]).update(is_deleted=1)
            return get_success_response("")
        else:
            return get_error_response(response_body_utils.PARAMS_MISSING)

    def details(self, request, **kwargs):
        if kwargs.get("pk"):
            data = ApiInfo.objects.get(id=kwargs["pk"])
            data = self.get_serializer(data).data
            return get_success_response(data)
        else:
            return get_error_response(response_body_utils.PARAMS_MISSING)

    def debug(self, request):
        api_info = self.get_serializer(request.data).data
        get_extractions_list = []
        api_request_result = send_http_request.execute_api_case(api_info, get_extractions_list)
        # 将api执行结果保存至数据库，写于核心方法中，后续不用重复编写
        serializer = ApiRequestResultModelSerializer(data=api_request_result)
        if serializer.is_valid():
            api_request_result_models = serializer.save()
            api_request_result_models = ApiRequestResult.objects.get(id=api_request_result_models.id)
            api_request_result_models = api_request_result_models.as_dict()
            return get_success_response(api_request_result_models)
        else:
            logging.error(serializer.errors)

    def upload_by_url(self, request):
        serializer = UploadByUrlSerializer(data=request.data)
        if serializer.is_valid():
            import_url = serializer.validated_data['import_url']
            project_id = serializer.validated_data['project_id']
            url = serializer.validated_data['url']
            base_path = serializer.validated_data['base_path']
            env_id = serializer.validated_data['env_id']
            response = requests.get(url=import_url, verify=True, timeout=20)  # 添加SSL验证和超时
            if response.status_code == 200:
                result = response.text  # 直接使用response.text来获取文本内容
                analysis_json(result, project_id, url, env_id, base_path, is_file=False)
                return get_success_response("")
            else:
                return get_error_response(f"Failed to retrieve content from {import_url}: {response.status_code}")
        else:
            return get_error_response(response_body_utils.PARAMS_MISSING)

    def step_syn(self, request, **kwargs):
        if kwargs.get("pk"):
            data = ApiInfo.objects.get(id=kwargs["pk"])
            data = ApiInfoModelSerializer(data).data
            step_list = TestCaseStep.objects.filter(api_id=kwargs.get("pk"), is_deleted=0, is_synchronized=False)
            # 同步步骤
            not_synced_steps = []
            for step in step_list:
                step_serializer = TestCaseStepModelSerializer(step, data=data, partial=True)
                if step_serializer.is_valid():
                    step_serializer.save()
                else:
                    not_synced_steps.append((step.id, step_serializer.errors))  # 收集错误和步骤ID
                    return get_error_response(response_body_utils.PARAMS_MISSING)
            not_syn_result = TestCaseStep.objects.filter(api_id=kwargs.get("pk"), is_deleted=0,
                                                         is_synchronized=True).values_list('test_case_id',
                                                                                           flat=True).distinct()
            # 如果同步时，出现了校验报错，返回报错结果，结果默认依旧是成功，仅给出失败内容
            if not_synced_steps:
                error_message = f"同步完成，其中不可同步测试用例id组:{list(not_syn_result)}\n"
                error_message += "同步过程中遇到错误，以下是详细信息：\n"
                for step_id, errors in not_synced_steps:
                    error_message += f"步骤ID: {step_id}, 错误: {errors}\n"
                return get_success_response(error_message)
            return get_success_response(f"同步完成，其中不可同步测试用例id组:{list(not_syn_result)}")
        else:
            return get_error_response(response_body_utils.PARAMS_MISSING)


class ApiInfoAddRequestHeaderListView(viewsets.GenericViewSet):
    queryset = ApiInfo.objects.all().filter(is_deleted=0).order_by("-update_time")
    serializer_class = ApiInfoAddRequestHeaderListSerializer

    def api_info_add_request_header_list(self, request):
        project_id = request.data.get("project_id")
        if not project_id:
            return get_error_response(response_body_utils.PARAMS_MISSING)

        request_header_list = request.data.get("request_header_list", [])
        errors = []

        # 使用列表推导式来构建新的request_header_list，避免多次序列化
        for api_info in self.get_queryset().filter(project_id=project_id):
            api_info_serializer = ApiInfoModelSerializer(api_info, partial=True)
            current_headers = api_info_serializer.data.get("request_header", [])

            # 使用字典来加速查找过程
            header_dict = {rh['key']: rh for rh in current_headers}
            new_headers = [request_header for request_header in request_header_list if
                           request_header.get('key') not in header_dict]
            api_info_serializer.data["request_header"] = new_headers + list(header_dict.values())
            if api_info_serializer.is_valid():
                api_info_serializer.save()
            else:
                errors.append((api_info.id, api_info_serializer.errors))
        if errors:
            error_message = "在更新API信息时遇到错误，以下是详细信息：\n"
            for api_id, errors in errors:
                error_message += f"API ID: {api_id}, 错误: {errors}\n"
            return get_error_response(error_message)
        return get_success_response("")


class ApiSuiteView(viewsets.GenericViewSet):
    queryset = ApiSuite.objects.all().filter(is_deleted=0).order_by("-update_time")
    serializer_class = ApiSuiteModelSerializer

    def add(self, request):
        name = request.data.get("name")
        project_id = request.data.get("project_id")
        if not name and not project_id:
            return get_error_response(response_body_utils.PARAMS_MISSING)
        if ApiTestModels.ApiSuite.objects.filter(name=name, project_id=project_id).first():
            return get_error_response(response_body_utils.DATA_DUPLICATION)

        else:
            # 反序列化
            serializer = ApiSuiteModelSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                return get_success_response("")
            else:
                logging.error(serializer.errors)
            return get_error_response(response_body_utils.PARAMS_MISSING)

    def list(self, request):
        get_queryset = self.get_queryset()
        data = list(get_queryset.values())
        return get_success_response(data)

    def api_suite_tree(self, request, project_id):
        api_suite_list = self.get_queryset().filter(project_id=project_id)
        api_suite_list = ApiSuiteModelSerializer(api_suite_list, many=True).data
        api_suite_tree = []
        for api_suite in api_suite_list:
            api_info = ApiInfo.objects.all().filter(api_suite_id=api_suite["id"], project_id=project_id,
                                                    is_deleted=0).order_by("-update_time")
            api_suite["api_info_list"] = ApiInfoModelSerializer(api_info, many=True).data
            api_suite_tree.append(api_suite)
        return get_success_response(api_suite_tree)

    def update(self, request):
        req_data = request.data
        if ApiSuite.objects.filter(id=req_data["id"]).first():
            ApiSuite.objects.filter(id=req_data["id"]).update(**req_data)
            return get_success_response("")
        else:
            return get_error_response(response_body_utils.DATA_ABSENT)


class TestCaseView(viewsets.GenericViewSet, PaginatedViewMixin):
    queryset = TestCase.objects.all().filter(is_deleted=0).order_by("-update_time")
    serializer_class = TestCaseModelSerializer
    pagination_class = StandardPagination  # 使用自定义的分页类

    def page(self, request):
        get_queryset = self.get_queryset()
        if request.query_params.get("project_id"):
            get_queryset = get_queryset.filter(project_id=request.query_params.get("project_id"))
        if request.query_params.get("name"):
            get_queryset = get_queryset.filter(name__icontains=request.query_params.get("name"))
        return super().base_page(request, get_queryset)

    def add(self, request):
        name = request.data["name"]
        project_id = request.data["project_id"]
        if self.get_queryset().filter(name=name, project_id=project_id).first():
            return get_error_response(response_body_utils.DATA_DUPLICATION)
        # 反序列化
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return get_success_response("")
        else:
            return get_error_response(response_body_utils.PARAMS_MISSING)

    def update(self, request):
        req_data = request.data
        if self.get_queryset().filter(id=req_data["id"], project_id=req_data["project_id"], is_deleted=0).first():
            self.get_queryset().filter(id=req_data["id"]).update(**req_data)
            return get_success_response("")
        else:
            return get_error_response(response_body_utils.DATA_ABSENT)

    def run(self, request):
        if request.data.get("id") and request.data.get("env_id"):
            test_case_result_dto = tes_case_run(request.data["id"], request.data["env_id"])
            # 对象转为json格式且不适用ascii格式
            return get_success_response(test_case_result_dto.__dict__)
        else:
            return get_error_response(response_body_utils.PARAMS_MISSING)

    def delete(self, request, **kwargs):

        if kwargs.get("pk"):
            self.get_queryset().filter(id=kwargs["pk"]).update(is_deleted=1)
            return get_success_response("")
        else:
            return get_error_response(response_body_utils.PARAMS_MISSING)


class TestCaseStepView(viewsets.GenericViewSet):
    queryset = TestCaseStep.objects.all().filter(is_deleted=0).order_by("-sort")
    serializer_class = TestCaseStepModelSerializer

    @swagger_auto_schema(
        request_body=TestCaseStepModelSerializer(many=True)
    )
    def add(self, request):
        sort = TestCase.objects.filter(id=request.data[0]["test_case_id"]).count()
        for step in request.data:
            sort += 1
            step["sort"] = sort
            # 反序列化
            serializer = TestCaseStepModelSerializer(data=step)
            if serializer.is_valid():
                serializer.save()
            else:
                logging.error(serializer.errors)
        return get_success_response("")


class TestCaseStepReqView(viewsets.GenericViewSet):
    queryset = TestCaseStep.objects.all().filter(is_deleted=0).order_by("sort")
    serializer_class = TestCaseStepReqSerializer

    def list(self, request):
        get_queryset = TestCaseStep.objects.all().filter(is_deleted=0, test_case_id=request.query_params.get(
            "test_case_id")).order_by("sort")
        data = self.get_serializer(get_queryset, many=True).data
        if TestCase.objects.filter(id=request.query_params.get("test_case_id"), is_deleted=0).first():
            env_id = TestCase.objects.get(id=request.query_params.get("test_case_id")).env_id
            for num in range(0, get_queryset.count()):
                test_case_processor_list = TestCaseProcessor.objects.filter(step_id=data[num]["id"])
                test_case_processor_list_serializer = TestCaseProcessorModelSerializer(test_case_processor_list,
                                                                                       many=True).data
                data[num]["test_case_processor_list"] = test_case_processor_list_serializer
                data[num]["env_id"] = env_id
        return get_success_response(data)

    def update_one(self, request):
        req_data = request.data
        if self.get_queryset().filter(id=req_data["id"], is_deleted=0).first():
            # 获取实例，后再根据实例序列化，后更新数据库
            instance = TestCaseStep.objects.get(id=req_data["id"])
            # partial=True 来配置是否仅更新部分数据
            req_data["is_synchronized"] = True
            serializer = TestCaseStepModelSerializer(instance, data=req_data, partial=True)
            if serializer.is_valid():
                serializer.save()
            else:
                logging.error(serializer.errors)
                return get_error_response(response_body_utils.PARAMS_MISSING)
            test_case_processor_list = req_data["test_case_processor_list"]
            for test_case_processor in test_case_processor_list:
                if TestCaseProcessor.objects.filter().filter(id=test_case_processor.get("id")).first():
                    TestCaseProcessor.objects.filter(id=test_case_processor["id"]).update(**test_case_processor)
                else:
                    processor_serializer = TestCaseProcessorModelSerializer(data=test_case_processor)
                    if processor_serializer.is_valid():
                        processor_serializer.save()
            return get_success_response("")
        else:
            return get_error_response(response_body_utils.DATA_ABSENT)

    def delete_one(self, request, **kwargs):
        if kwargs.get("pk"):
            self.get_queryset().filter(id=kwargs["pk"]).update(is_deleted=1)
            return get_success_response("")
        else:
            return get_error_response(response_body_utils.PARAMS_MISSING)

    @swagger_auto_schema(
        request_body=TestCaseStepReqSerializer(many=True)
    )
    def update_sort(self, request):
        req_data = request.data
        sort = 0
        if req_data.get("env_id") and req_data.get("apiTestCaseStepReqs"):
            TestCase.objects.filter(id=req_data["apiTestCaseStepReqs"][0].get("test_case_id")).update(
                env_id=req_data.get("env_id"))
        for test_case_step in req_data["apiTestCaseStepReqs"]:
            sort += 1
            if TestCaseStep.objects.filter(id=test_case_step["id"], is_deleted=0).first():
                TestCaseStep.objects.filter(id=test_case_step["id"], is_deleted=0).update(sort=sort)
        return get_success_response("")


class TestCaseGroupView(viewsets.GenericViewSet):
    queryset = TestCaseGroup.objects.all().filter(is_deleted=0).order_by("-update_time")
    serializer_class = TestCaseGroupModelSerializer

    def add(self, request):
        name = request.data["name"]
        project_id = request.data["project_id"]
        if ApiTestModels.TestCaseGroup.objects.filter(name=name, project_id=project_id).first():
            return get_error_response(response_body_utils.DATA_DUPLICATION)
        # 反序列化
        serializer = TestCaseGroupModelSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return get_success_response("")
        else:
            logging.error(serializer.errors)
            return get_error_response(response_body_utils.PARAMS_MISSING)

    def update(self, request):
        req_data = request.data
        if self.get_queryset().filter(id=req_data["id"], is_deleted=0).first():
            self.get_queryset().filter(id=req_data["id"]).update(**req_data)
            return get_success_response("")
        else:
            return get_error_response(response_body_utils.DATA_ABSENT)

    # @swagger_auto_schema(
    #     manual_parameters=[
    #         openapi.Parameter(
    #             "test_case_group_id", in_=openapi.IN_QUERY,
    #             type=openapi.TYPE_INTEGER
    #         ),
    #         openapi.Parameter(
    #             "env_id", in_=openapi.IN_QUERY,
    #             type=openapi.TYPE_INTEGER
    #         )
    #     ]
    # )
    def run(self, request, **kwargs):
        test_case_group_result = group_run(kwargs.get("test_case_group_id"), kwargs.get("env_id"))
        return get_success_response(test_case_group_result)

    def list(self, request):
        get_queryset = self.get_queryset()
        if request.query_params.get("project_id"):
            get_queryset = get_queryset.filter(project_id=request.query_params.get("project_id"))
        data = self.get_serializer(get_queryset, many=True).data
        return get_success_response(data)


class TestCaseGroupCaseListView(viewsets.GenericViewSet):
    queryset = TestCaseGroup.objects.all().prefetch_related('test_case_merge')  # 优化查询
    serializer_class = TestCaseInGroupSerializer

    # 如果你要覆盖list方法来添加额外的逻辑，可以这样做：
    def case_list(self, request):
        queryset = self.filter_queryset(self.get_queryset())
        if request.query_params.get("test_group_id"):
            try:
                queryset = queryset.get(id=request.query_params.get("test_group_id"))
                serializer = self.get_serializer(queryset)
                return get_success_response(serializer.data)
            except ObjectDoesNotExist:
                # 不存在test_group_id 抛出异常依旧返回结果，且正常返回
                return get_success_response({})
        else:
            return get_error_response(response_body_utils.PARAMS_MISSING)


class TestCaseGroupCreateUpdateView(viewsets.GenericViewSet):
    queryset = TestCaseGroup.objects.all().filter(is_deleted=0).order_by("-update_time")
    serializer_class = TestCaseGroupCreateUpdateSerializer

    def add(self, request):
        group, _ = TestCaseGroup.objects.get_or_create(id=request.data["group_id"])  # 如果groupId是主键
        serializer = self.get_serializer(group, data=request.data)
        if serializer.is_valid():
            serializer.save()
        else:
            logging.error(serializer.errors)
        return get_success_response("")

    def delete(self, request):
        group, _ = TestCaseGroup.objects.get_or_create(id=request.data["group_id"])  # 如果groupId是主键
        test_case_ids = request.data.pop('test_case_ids')
        test_cases = TestCase.objects.filter(id__in=test_case_ids)
        for test_case in test_cases:
            group.test_case_merge.remove(test_case)
        # serializer = self.get_serializer(group, data=request.data)
        # if serializer.is_valid():
        #     serializer.save()
        # else:
        #     print(serializer.errors)
        return get_success_response("")


class FileUploadViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    queryset = None  # 因为我们不使用数据库模型，所以这里为None
    serializer_class = FileUploadSerializer
    parser_classes = (MultiPartParser, FormParser)  # 用于处理文件上传

    def upload_file(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        file = serializer.validated_data['file']

        # 指定你想要保存文件的目录
        upload_dir = settings.JSON_API_MEDIA_ROOT

        # 确保目录存在
        if not os.path.exists(upload_dir):
            os.makedirs(upload_dir)

            # 保存文件
        file_path = os.path.join(upload_dir, file.name)
        with open(file_path, 'wb+') as destination:
            for chunk in file.chunks():
                destination.write(chunk)

        #         # 读取文件内容并转为字符串（假设文件是文本文件）
        # with open(file_path, 'r', encoding='utf-8') as f:
        #     content = f.read()
        if request.data.get("project_id") and request.data.get("url") and request.data.get(
                "base_path") and request.data.get("env_id"):
            analysis_json(file_path, request.data.get("project_id"), request.data.get("url"),
                          request.data.get("env_id"), request.data.get(
                    "base_path"))
            return get_success_response("")
        else:
            return get_error_response(response_body_utils.PARAMS_MISSING)
